#include "BankManagement.h"

float getFloat()
{
	float temp;
	while (!(cin >> temp))
	{
		cout << "Wrong input. Please, try again: ";
		cin.clear();
	}
	return temp;
}
int getInt()
{
	int temp;
	while (!(cin >> temp))
	{
		cout << "Wrong input. Please, try again: ";
		cin.clear();
	}
	return temp;
}
int showMenu()
{
	int select;

	cout << "    \n\nBank Management:"	<< endl;
	cout << "01. Add new employee"		<< endl;
	cout << "02. Add new client"		<< endl;
	cout << "03. Create new account"	<< endl;

	cout << "04. Deposit Money"			<< endl;
	cout << "05. Withdraw Money"		<< endl;

	cout << "06. Give bonus"			<< endl;
	cout << "07. Give VIP status"		<< endl;
	
	cout << "08. Remove Employee"		<< endl;
	cout << "09. Remove client"			<< endl;
	cout << "10. Delete account"		<< endl;

	cout << "11. Show all Employees"	<< endl;
	cout << "12. Show all Clients"		<< endl;
	cout << "13. Show all Accounts"		<< endl;


	cout << "15. Quit"					<< endl;
	cout << "Enter your selection:"		<< endl;

	select = getInt();
	return select;
}
int showAllCashiers()
{
	cout << "Cashiers:" << endl;
	const vector<Employee*>* cashiers = BankBranch::Instance()->getCashiers();
	printEmployees(cashiers);
	
	int size = cashiers->size();
	delete cashiers;
	return size;
}

int showAllClerks()
{
	cout << "Clerks:" << endl;
	const vector<Employee*>* clerks = BankBranch::Instance()->getClerks();
	printEmployees(clerks);

	int size = clerks->size();
	delete clerks;

	return size;
}

void showAllEmployees()
{
	const Director* director;

	director = &BankBranch::Instance()->getBrachDirector();

	cout << "Director:\n";
	if (director != NULL)
	{
		cout << *director << "\n";
	}


	if (showAllCashiers() == 0)
	{
		cout << "No casheirs found" << endl;
	}

	if (showAllClerks() == 0)
	{
		cout << "No clerks found" << endl;
	}
	

}
void addClerk()
{
	int age, salary;
	string firstName;
	string lastName;
	Clerk::eGender gender;

	cout << "\nEnter  first name: ";
	cin >> firstName;
	cout << "\nEnter  last name: ";
	cin >> lastName;
	cout << "\nEnter  gender: 1 - for male , 2 - for female : ";
	gender = (Clerk::eGender)getInt();
	cout << "\nEnter  age: ";
	age = getInt();
	cout << "\nEnter salary: ";
	salary = getInt();

	Clerk* clerk = new Clerk(firstName, lastName, age, gender, salary, 0);
	BankBranch::Instance()->addEmployee(*clerk);
}
void addCashier()
{
	int age, salary;
	string firstName;
	string lastName;
	Person::eGender gender;
	int numOfVacationDays;

	cout << "\nEnter  first name: ";
	cin >> firstName;
	cout << "\nEnter  last name: ";
	cin >> lastName;
	cout << "\nEnter  gender: 1 - for male , 2 - for female : ";
	gender = (Person::eGender)getInt();
	cout << "\nEnter  age: ";
	age = getInt();
	cout << "\nEnter salary: ";
	salary = getInt();
	cout << "\nEnter  Vacation Days: ";
	numOfVacationDays = getInt();

	Cashier* cashier = new Cashier(firstName, lastName, age, gender, salary, numOfVacationDays);
	BankBranch::Instance()->addEmployee(*cashier);
}
void addDirector()
{
	int age, salary;
	string firstName;
	string lastName;
	Director::eGender gender;
	string educaton;
	float overheadHours;
	int experience;
	int numOfVacationDays;

	cout << "\nEnter  first name: ";
	cin >> firstName;
	cout << "\nEnter  last name: ";
	cin >> lastName;
	cout << "\nEnter  gender: 1 - for male , 2 - for female : ";
	gender = (Director::eGender)getInt();
	cout << "\nEnter  age: ";
	age = getInt();
	cout << "\nEnter salary: ";
	salary = getInt();
	cout << "\nEnter  Education: ";
	cin >> educaton;
	cout << "\nEnter  Overhead Hourse: ";
	overheadHours = getFloat();
	cout << "\nEnter  Experience: ";
	experience = getInt();
	cout << "\nEnter  Vacation Days: ";
	numOfVacationDays = getInt();

	Director* director = new Director(firstName, lastName, age, gender, salary, 0, numOfVacationDays, educaton, overheadHours, experience);

	BankBranch::Instance()->updateDirector(*director);
}
void addEmployee()
{
	int select;
	cout << "    Choose Employee to add:" << endl;
	cout << "1.  Clerk" << endl;
	cout << "2.  Cashier" << endl;
	cout << "3.  Director" << endl;
	cout << "Enter your selection:" << endl;
	select = getInt();
	switch (select)
	{
	case 1:
		addClerk();
		break;
	case 2:
		addCashier();
		break;
	case 3:
		addDirector();
		break;
	default:
		break;
	}
}
int printEmployees(const vector<Employee*>* employees)
{
	vector<Employee*>::const_iterator itEmployees = employees->begin();

	for (; itEmployees != employees->end(); ++itEmployees)
	{
		cout << **itEmployees << endl;
	}

	return employees->size();
}

const Date& getDateDetails()
{
	int day;
	Date::eMonth month;
	int year;
	int hour;
	int minutes;

	cout << "\nChoose day (1-31): ";
	day = getInt();
	cout << "\nChoose month(1-12): ";
	month = (Date::eMonth)getInt();
	cout << "\nEnter year: ";
	year = getInt();
	cout << "\nEnter hour(1-24): ";
	hour = getInt();
	cout << "\nEnter minutes(0-59): ";
	minutes = getInt();

	return *(new Date(day, month, year, hour, minutes));
}
Contact& getContactDetails()
{
	int zipcode;
	string phoneNumber;
	string city;

	cout << "\nEnter city: ";
	cin >> city;
	cout << "\nEnter zip code: ";
	zipcode = getInt();
	cout << "\nEnter phone number: ";
	cin >> phoneNumber;
	return *(new Contact(city, phoneNumber, zipcode));
}

int showAllClients()
{
	const vector<Client*> clients = BankBranch::Instance()->getClients();
	cout << "Bank clients:" << endl;
	vector<Client*>::const_iterator	itClients;

	for (itClients = clients.begin(); itClients != clients.end(); ++itClients)
	{
		cout <<**itClients << endl;
	}

	return clients.size();
}
void addClient()
{
	int age;
	string firstName;
	string lastName;
	Client::eGender gender;


	cout << "\nEnter  first name: ";
	cin >> firstName;
	cout << "\nEnter  last name: ";
	cin >> lastName;
	cout << "\nEnter  gender: 1 - for male , 2 - for female : ";
	gender = (Client::eGender)getInt();
	cout << "\nEnter  age: ";
	age = getInt();

	Contact contact = getContactDetails();


	Client* client = new Client(firstName, lastName, age, gender, contact);

	BankBranch::Instance()->addClient(*client);
}

Account* getCurrentAccount()
{
	Account* currentAccount = NULL;

	int balance;

	cout << "\nEnter balance: ";
	cin >> balance;

	const Date* creationDate = Date::Now();

	currentAccount = new CurrentAccount(balance, *creationDate);

	return currentAccount;
}
Account* getSavingAccount()
{
	Account* savingAccount = NULL;

	int balance;
	float depositPercent;

	cout << "Enter balance: " << endl;
	cin >> balance;

	cout << "Enter saving Date: " << endl;
	const Date creationDate = getDateDetails();

	cout << "Enter deposit percent" << endl;
	depositPercent = getFloat();

	savingAccount = new SavingsAccount(balance, creationDate, depositPercent);

	return savingAccount;
}

Account* createAccount(int accountType)
{
	int id;

	Account* currentAccount = NULL;

	cout << "Clerks list:\n";


	if (showAllClerks() > 0)
	{
		cout << "Type clerk's id that open account: ";
		id = getInt();

		try
		{
			Clerk* clerk = dynamic_cast<Clerk*>(BankBranch::Instance()->getEmployeeByID(id));

			if (clerk == NULL)
			{
				throw std::exception("Employee not found.");
			}

			clerk->increaseOpennedAccounts();

			if (accountType == 1)
			{
				currentAccount = getCurrentAccount();
			}
			else
			{
				currentAccount = getSavingAccount();
			}
			
		}
		catch (const std::exception &ex)
		{
			cout << ex.what();
		}
	}
	else
	{
		cout << "\nNo available clerks to handle your request please try again later";
	}

	return currentAccount;
}
void addAccount()
{
	int select;
	int clientId;

	Account* account = NULL;
	Client* client = NULL;

	cout << "Enter client id:";
	clientId = getInt();

	try
	{
		client = BankBranch::Instance()->getClientByID(clientId);
	}
	catch (...)
	{
		cout << "No client found" << endl;
		return;
	}

	cout << "Choose account type" << endl;
	cout << "1. Current account" << endl;
	cout << "2. Saving account" << endl;
	select = getInt();

	try{
		switch (select)
		{
			case 1:
				account = createAccount(select);
				if (account != NULL)
				{
					client->updateCurrentAccount(*account);
					cout << "Account added successfully." << endl;
				}
				break;
			case 2:
				if (!client->getVipStatus())
				{
					cout << "Only VIP clients can get saving account" << endl;
				}
				else
				{
					account = createAccount(select);
					if (account != NULL)
					{
						client->addSavingAccount(dynamic_cast<SavingsAccount*>(account));
						cout << "Account added successfully." << endl;
					}
				}

				break;
			default:
				cout << "Account added successfully." << endl;
				break;
		}
	}
	catch (std::exception ex)
	{
		cout << ex.what() << endl;
	}
}

void giveVipStatus()
{
	int clientId;

	Client* client = NULL;

	cout << "Enter client id:";
	clientId = getInt();

	try
	{
		client = BankBranch::Instance()->getClientByID(clientId);
	}
	catch (const std::exception &ex)
	{
		cout << ex.what() << endl;
		return;
	}

	client->setVipStatus(true);

	cout << "VIP status has been set to client with id: " << clientId;
}

void giveBonus()
{
	cout << "Enter bonus value" << endl;
	int bonus = getInt();

	Clerk::updateBonusPerOppenedAccount(bonus);
}

void doChashierAction(Transaction::eTransactionType tType)
{
	int cashierId;
	int clientId;
	int money;

	Cashier* cashier = NULL;
	Client*  client = NULL;
	
	try
	{
		if (showAllCashiers() > 0)
		{

			cout << "Enter chashier id: ";
			cashierId = getInt();

			cashier = dynamic_cast<Cashier*>(BankBranch::Instance()->getEmployeeByID(cashierId));

			if (cashier != NULL)
			{
				if (showAllClients() > 0)
				{

					cout << "Enter client id: ";
					clientId = getInt();

					client = BankBranch::Instance()->getClientByID(clientId);

					cout << "Money: ";
					money = getInt();

					if (tType == Transaction::eTransactionType::Deposite)
					{
						cashier->depositMoney(*client, money);
					}
					else if (tType == Transaction::eTransactionType::Withdrawal)
					{
						cashier->withdrawMoney(*client, money);
					}
				}
				else
				{
					cout << "No clients found" << endl;
				}
			}
		}
		else
		{
			cout << "No casheirs found" << endl;
		}
	}
	catch (std::exception ex)
	{
		cout << ex.what() << endl;
		return;
	}
	
}

void depositMoney()
{
	doChashierAction(Transaction::eTransactionType::Deposite);
}

void withdrawMoney()
{
	doChashierAction(Transaction::eTransactionType::Withdrawal);
}

void removeEmployee()
{
	cout << "Enter employee id:";
	int employeeId = getInt();

	if (BankBranch::Instance()->RemoveEmployee(employeeId))
	{
		cout << "Employee successfully removed.";
	}
	else
	{
		cout << "An error accured while removing employee";
	}
}

void removeClient()
{
	cout << "Enter client id:";
	int clientId = getInt();


	if (BankBranch::Instance()->removeClientById(clientId))
	{
		cout << "Client successfully removed.";
	}
	else
	{
		cout << "An error accured while removing client";
	}
}

void deleteAccount()
{

	int select;
	int clientId;

	Account* account = NULL;
	Client* client = NULL;

	cout << "Enter client id:";
	clientId = getInt();

	try
	{
		client = BankBranch::Instance()->getClientByID(clientId);
	}
	catch (const std::exception &ex)
	{
		cout << ex.what() << endl;
		return;
	}

	cout << "Choose account type" << endl;
	cout << "1. Current account" << endl;
	cout << "2. Saving account" << endl;
	select = getInt();

	switch (select)
	{
	case 1:
		if (client->removeCurrentAccount())
		{
			cout << "\nAccount removed successfully.";
		}
		else
		{
			cout << "Account does not exist.";
		}
		break;
	case 2:
		
		try
		{
			const vector<SavingsAccount*> savingsAccounts = client->getAllSavingsAccounts();

			vector<SavingsAccount*>::const_iterator	itAccounts;
			for (itAccounts = savingsAccounts.begin(); itAccounts != savingsAccounts.end(); ++itAccounts)
			{
				cout << **itAccounts << endl;
			}

			cout << "Select an account id from the list above: ";
			int accountId = getInt();

			client->removeSavingAccount(accountId);		
			cout << "Account removed successfully.";
			

		}
		catch (const std::exception &ex)
		{
			cout << ex.what();
			return;
		}

		break;
	default:
		break;
	}

	
}

void showAllAccounts()
{
	
	int totalAccounts = 0;
	int clientsCount = 0;
	const vector<Client*> clients = BankBranch::Instance()->getClients();
	
	vector<Client*>::const_iterator	itClients;
	for (itClients = clients.begin(); itClients != clients.end(); ++itClients)
	{

		int savingAccountsCount = 0;

		try{
			const vector<SavingsAccount*> savingsAcounts = (*itClients)->getAllSavingsAccounts();

			vector<SavingsAccount*>::const_iterator	itAccounts;
			for (itAccounts = savingsAcounts.begin(); itAccounts != savingsAcounts.end(); ++itAccounts)
			{
				cout << **itAccounts << endl;
				totalAccounts++;
			}
		}
		catch (...)
		{
		}

		const Account* currentAccount = (*itClients)->getCurrentAccount();
		if (currentAccount != NULL)
		{
			cout << *currentAccount << endl;
			totalAccounts++;
		}
	}

	cout << "\n\n" << totalAccounts  << " accounts found." <<endl;
	
}

void main()
{
	bool run = true;

	while (run)
	{
		switch (showMenu())
		{
		case 1: //Add new employee
			addEmployee();
			break;
		case 2: //Add new client
			addClient();
			break;
		case 3: //Create new account
			addAccount();
			break;
		case 4: //Deposit Money
			depositMoney();
			break;
		case 5: //Withdraw Money
			withdrawMoney();
			break;
		case 6: //Give bonus
			giveBonus();
			break;
		case 7: //Give VIP status
			giveVipStatus();
			break;
		case 8: //Remove Employee
			removeEmployee();
			break;
		case 9: //Remove client
			removeClient();
			break;
		case 10: //Delete account
			deleteAccount();
			break;
		case 11: //Show all Employees
			showAllEmployees();
			break;
		case 12: //Show all Clients
			if (showAllClients() == 0)
			{
				cout << "No clients found." << endl;
			}
			break;
		case 13: //Show all Accounts
			showAllAccounts();
			break;
		case 15: //Quit

			cout << "Quiting..." << endl;
			run = false;

			break;
		default:
			cout << "No such option. Please choose again:  " << endl;
			break;
		}
	}


}

